package cn.zzdt4j.common.extension.design;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import lombok.extern.slf4j.Slf4j;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * The type Abstract subject center.
 *
 * @author by <a href="mailto:ligang941012@gmail.com">gang.Li</a>
 * @since 2023 /11/8 14:56
 */
@Slf4j
@SuppressWarnings("unchecked")
public class AbstractSubjectCenter {
    private static final Map<String, List<Observer>> OBSERVERS_MAP = new ConcurrentHashMap<>();

    /**
     * Register observer.
     *
     * @param observer the observer
     */
    public static void register(Observer observer) {
        register(SubjectType.SPRING_CONTENT_REFRESHED.name(), observer);
    }

    /**
     * Register observer.
     *
     * @param subjectType the subject type
     * @param observer    the observer
     */
    public static void register(SubjectType subjectType, Observer observer) {
        register(subjectType.name(), observer);
    }

    /**
     * Register observer.
     *
     * @param subject  the name
     * @param observer the observer
     */
    public static void register(String subject, Observer observer) {
        if (StrUtil.isBlank(subject) || observer == null) {
            log.warn("Register observer. A string whose subject or observer is empty or empty.");
            return;
        }
        List<Observer> observers = OBSERVERS_MAP.get(subject);
        if (CollectionUtil.isEmpty(observers)) {
            observers = new ArrayList<>();
        }
        observers.add(observer);
        OBSERVERS_MAP.put(subject, observers);
    }

    /**
     * Remove observer.
     *
     * @param observer the observer
     */
    public static void remove(Observer observer) {
        remove(SubjectType.SPRING_CONTENT_REFRESHED.name(), observer);
    }

    /**
     * Remove observer.
     *
     * @param subject  the subject
     * @param observer the observer
     */
    public static void remove(String subject, Observer observer) {
        final List<Observer> observers = OBSERVERS_MAP.get(subject);
        if (StrUtil.isBlank(subject) || CollectionUtil.isEmpty(observers) || observer == null) {
            log.warn("Remove observer. A string whose subject or observer is empty or empty.");
            return;
        }
        observers.remove(observer);
    }

    /**
     * Notify observer.
     *
     * @param observerMessage the observer message
     */
    public static void notify(SubjectType subjectType,ObserverMessage observerMessage) {
        notify(subjectType.name(), observerMessage);
    }

    /**
     * Notify observer.
     *
     * @param subject         the subject
     * @param observerMessage the observer message
     */
    public static void notify(String subject, ObserverMessage observerMessage) {
        final List<Observer> observers = OBSERVERS_MAP.get(subject);
        if (CollectionUtil.isEmpty(observers)) {
            log.warn("Under the subject , there is no observer group.");
            return;
        }
        observers.parallelStream().forEach(each -> {
            try {
                each.accept(observerMessage);
            } catch (Exception e) {
                log.error("Notification subject: {} observer exception", subject);
            }
        });
    }

    /**
     * The enum Subject type.
     */
    public enum SubjectType {
        /**
         * Spring content refreshed subject type.
         */
        SPRING_CONTENT_REFRESHED,
        /**
         * Clear config cache subject type.
         */
        CLEAR_CONFIG_CACHE,

        /**
         * Thread pool dynamic refresh subject type.
         */
        THREAD_POOL_DYNAMIC_REFRESH
    }
}
